﻿using Shop.Core.Helper;
using Shop.Core.Repository;
using Shop.Core.Share;
using Shop.IServices.Admin;
using Shop.Model.Dto.Admin.Use;
using Shop.Model.Entity.Jur;
using Shop.Model.Entity.Order;
using Shop.Model.Entity.Use;
using Shop.Model.View.Admin.User;
using SqlSugar;

namespace Shop.Services.Admin;

public class UseService: AbstractService, IUseService
{
    private readonly RepositoryBase<UseUser> _userRepository;
    private readonly RepositoryBase<UserGradeLog> _gradeLogRepository;
    private readonly RepositoryBase<UserWalletLog> _walletLogRepository;
    private readonly RepositoryBase<UserWallet> _walletRepository;
    private readonly RepositoryBase<JurUser> _jurUserRepository;
    private readonly RepositoryBase<UserContract> _contractRepository;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="userRepository"></param>
    /// <param name="gradeLogRepository"></param>
    /// <param name="walletLogRepository"></param>
    /// <param name="walletRepository"></param>
    /// <param name="jurUserRepository"></param>
    /// <param name="contractRepository"></param>
    public UseService(
        RepositoryBase<UseUser> userRepository,
        RepositoryBase<UserGradeLog> gradeLogRepository,
        RepositoryBase<UserWalletLog> walletLogRepository,
        RepositoryBase<UserWallet> walletRepository,
        RepositoryBase<JurUser> jurUserRepository,
        RepositoryBase<UserContract> contractRepository)
    {
        _userRepository = userRepository;
        _gradeLogRepository = gradeLogRepository;
        _walletLogRepository = walletLogRepository;
        _walletRepository = walletRepository;
        _jurUserRepository = jurUserRepository;
        _contractRepository = contractRepository;
    }

    /// <summary>
    /// 用户列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult<PageModel<UserListVo>> UserList(UserListDto dto)
    {
        var records = 0;
        var data = _userRepository.Queryable<UseUser, UseUser, UserWallet>((t1, t2, t3) => new object[]
            {
                JoinType.Left, t1.SuperiorUser == t2.Id,
                JoinType.Left, t1.Id == t3.UserId
            })
            .WhereIF(!string.IsNullOrEmpty(dto.Name), (t1, t2, t3) => t1.Nickname.Contains(dto.Name))
            .WhereIF(!string.IsNullOrEmpty(dto.Tele), (t1, t2, t3) => t1.Tele == dto.Tele)
            .WhereIF(dto.Id.HasValue, (t1, t2, t3) => t1.Code == dto.Id.Value)
            .WhereIF(dto.Grade.HasValue && dto.Grade.Value != -1, (t1, t2, t3) => t1.Grade == dto.Grade.Value)
            .WhereIF(dto.State.HasValue, (t1, t2, t3) => t1.State == dto.State.Value)
            .WhereIF(dto.StartTime.HasValue, (t1, t2, t3) => t1.CreatTime >= dto.StartTime.Value)
            .WhereIF(dto.EndTime.HasValue, (t1, t2, t3) => t1.CreatTime < dto.EndTime.Value)
            .OrderByDescending((t1,t2, t3) => t1.CreatTime)
            .Select((t1, t2, t3) => new UserListVo()
            {
                Id = t1.Id,
                Code = t1.Code,
                Nickname = t1.Nickname,
                Tele = t1.Tele,
                SuperiorUserCode = t2.Code,
                SuperiorUserName = t2.Nickname,
                SuperiorUserTele = t2.Tele,
                State = t1.State,
                Balance = t3.Balance,
                CreatTime = t1.CreatTime,
                Grade = t1.Grade
            })
            .ToPageList(dto.PageIndex, dto.PageSize, ref records);
        foreach (var item in data)
        {
            if (string.IsNullOrEmpty(item.Nickname))
                item.Nickname = "昵称未授权";
            if (string.IsNullOrEmpty(item.Tele))
                item.Tele = "手机号未授权";
        }
        return new PageModel<UserListVo>(dto, data, records);
    }
    
    /// <summary>
    /// 修改用户上级
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="dto"></param>
    /// <returns></returns>
    public async Task<AppResult<bool>> ChangeSuperior(long userId, SuperiorChangeDto dto)
    {
        var user = await _userRepository.GetFirstAsync(x => x.Code == dto.UserId);
        if (user == null)
            return Problem($"参数错误，找不到用户[Code:{dto.UserId}]");
        if (user.Id == dto.SuperiorId)
            return Problem("不能设置自己为自己的上级");

        var superior = await _userRepository.GetFirstAsync(x => x.Id == dto.SuperiorId);
        if (superior == null)
            return Problem($"参数错误，上级用户不存在");

        if (superior.Id == user.SuperiorUser)
            return Problem($"不能设置当前用户的直属上级为新的直属上级");

        var exit = await _userRepository.Queryable<UseUserRelation>().AnyAsync(x => x.Descendant.Equals(superior.Id) && x.Ancestor.Equals(user.Id));
        if (exit)
            return Problem("操作失败，新的上级是用户现在的下级");

        var log = new ChangeSuperiorLog
        {
            UserId = user.Id,
            CeateTime = DateTime.Now,
            Desc = dto.Desc,
            ChangeBeforeUser = user.SuperiorUser,
        };
        try
        {
            _userRepository.BeginTran();
            var relationDb = _userRepository.Change<UseUserRelation>();
            var supIds = await relationDb.AsQueryable().Where(x => x.Descendant == user.Id).Select(x => x.Ancestor).ToArrayAsync();
            var sub = await relationDb.AsQueryable().Where(x => x.Ancestor == user.Id).ToArrayAsync();
            var subIds = sub.Select(x => x.Descendant).ToList();
            subIds.Add(user.Id);


            await relationDb.AsDeleteable().Where(x => supIds.Contains(x.Ancestor) && subIds.Contains(x.Descendant)).ExecuteCommandAsync();
            var newSup = await relationDb.AsQueryable().Where(x => x.Descendant == superior.Id).ToListAsync();
            newSup.Add(new UseUserRelation()
            {
                Level = 0,
                Ancestor = superior.Id
            });

            List<UseUserRelation> relations = new();
            foreach (var sup in newSup)
            {
                relations.Add(new UseUserRelation
                {
                    Id = IdGenerater.GetNextId(),
                    Level = sup.Level + 1,
                    Ancestor = sup.Ancestor,
                    Descendant = user.Id,
                    CreateTime = DateTime.Now,
                });
                foreach (var item in sub)
                {
                    relations.Add(new UseUserRelation
                    {
                        Id = IdGenerater.GetNextId(),
                        Level = item.Level + sup.Level + 1,
                        Ancestor = sup.Ancestor,
                        Descendant = item.Descendant,
                        CreateTime = DateTime.Now,
                    });
                }
            }

            await relationDb.InsertRangeAsync(relations);
            user.SuperiorUser = superior.Id;
            _userRepository.Update(user);

            log.ChangeLaterUser = user.SuperiorUser;
            log.Operation = userId;
            await _userRepository.Change<ChangeSuperiorLog>().InsertAsync(log);

            _userRepository.CommitTran();
        }
        catch (Exception ex)
        {
            _userRepository.RollbackTran();
            return Problem(ex.Message);
        }
        return Success();
    }
    
    /// <summary>
    /// 调整级别
    /// </summary>
    /// <param name="dto"></param>
    /// <param name="uId"></param>
    /// <returns></returns>
    public AppResult UpUserGrade(UpUserGradeDto dto, long uId)
    {
        if (dto.ChangeLaterGrade > 3 || dto.ChangeLaterGrade < 0)
            return Problem("调整级别错误");
        var userInfo = _userRepository.Where(x => x.Id == dto.UserId).First();
        if (userInfo == null)
            return Problem("用户不存在");
        if (dto.ChangeLaterGrade == 3)
        {
            var useContract = _contractRepository.Where(x => x.UserId == dto.UserId && x.State == 1).First();
            if (useContract == null)
                userInfo.Audit = 1;
        }
        var userGradeLog = new UserGradeLog()
        {
            UserId = userInfo.Id,
            ChangeFrontGrade = userInfo.Grade,
            ChangeLaterGrade = dto.ChangeLaterGrade,
            Title = $"管理员：{uId}调整,{dto.Title}"
        };
        _gradeLogRepository.Insert(userGradeLog);
        userInfo.Grade = dto.ChangeLaterGrade;
        _userRepository.Update(userInfo);
        return new AppResult();
    }

    /// <summary>
    /// 调整状态
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult UpUserState(UpUserStateDto dto)
    {
        var isBool = dto.ChangeLaterState switch
        {
            -2 => true,
            -1 => true,
            0 => true,
            1 => true,
            2 => true,
            _ => false
        };
        if (!isBool)
            return Problem("状态错误");
        var userInfo = _userRepository.Where(x => x.Id == dto.UserId).First();
        if (userInfo == null)
            return Problem("用户不存在");
        if (userInfo.State == dto.ChangeLaterState)
            return Problem("用户以是此状态！");
        userInfo.State = dto.ChangeLaterState;
        _userRepository.Update(userInfo);
        return new AppResult();
    }

    /// <summary>
    /// 用户明细
    /// </summary>
    /// <param name="uId"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult<UseInfoVo> UseInfo(long uId)
    {
        var data = _userRepository.Queryable<UseUser, UseUser, UserWallet>((t1, t2, t3) => new object[]
            {
                JoinType.Left, t1.SuperiorUser == t2.Id,
                JoinType.Left, t1.Id == t3.UserId
            })
            .Where((t1, t2, t3) => t1.Id == uId)
            .Select((t1, t2, t3) => new UseInfoVo()
            {
                Id = t1.Id,
                Code = t1.Code,
                Nickname = t1.Nickname,
                Head = t1.Head,
                Tele = t1.Tele,
                State = t1.State,
                CreatTime = t1.CreatTime,
                Grade = t1.Grade,
                SuperiorCode = t2.Code,
                SuperiorName = t2.Nickname,
                SuperiorTele = t2.Tele,
                Balance = t3.Balance,
                Brokerage = t3.Brokerage,
                Bonus = t3.Bonus,
                Dividend = t3.Dividend,
                Surplus = t3.Surplus,
                Withdrawable = t3.Withdrawable
            })
            .First();
        return data;
    }

    /// <summary>
    /// 用户钱包明细
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult<PageModel<UseWelletVo>> UseWellet(UseWelletDto dto)
    {
        var records = 0;
        var data = _walletLogRepository.Queryable<UserWalletLog, Orders, UseUser>((t1, t2, t3) => new object[]
            {
                JoinType.Left, t1.SourceOrder == t2.Id,
                JoinType.Left, t2.UserId == t3.Id
            })
            .Where((t1, t2, t3) => t1.UserId == dto.Id)
            .OrderBy("t1.CreateTime DESC")
            .Select((t1, t2, t3) => new UseWelletVo()
            {
                Action = t1.Action == 1 ? "订单付款" :
                    t1.Action == 2 ? "提现" :
                    t1.Action == 3 ? "佣金" :
                    t1.Action == 4 ? "动态分红（服务费）" :
                    t1.Action == 5 ? "定期分红" : 
                    t1.Action == 6 ? "后台调整-增加" :
                    t1.Action == 7 ? "后台调整-减少" :"用户退款",
                OrderCode = t2.Code,
                OrderUser = t3.Nickname,
                Amount = t1.Amount,
                State = t1.State == -1 ? "处理失败" : t1.State == 0 ? "处理中" : "处理成功",
                Title = t1.Title,
                CreateTime = t1.CreateTime,
                FinishTime = t1.FinishTime
            })
            .ToPageList(dto.PageIndex, dto.PageSize, ref records);
        return new PageModel<UseWelletVo>(dto, data, records);
    }

    /// <summary>
    /// 钱包调整
    /// </summary>
    /// <param name="dto"></param>
    /// <param name="uId"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult WelletAdjust(WelletAdjustDto dto, long uId)
    {
        if (dto.Amount <= 0)
            return Problem("调整金额不可小于0");
        if (dto.State != 1 && dto.State != 2)
            return Problem("操作错误");
        var useInfo = _userRepository.Where(x => x.Id == dto.UId).First();
        if (useInfo == null)
            return Problem("用户信息错误");
        var useBalanceInfo = _walletRepository.Where(x => x.UserId == dto.UId).First();
        var useWalletLog = new UserWalletLog();
        if (dto.State == 1)
        {
            useBalanceInfo.Balance += dto.Amount;
            useWalletLog.Action = 6;
        }

        if (dto.State == 2)
        {
            if (dto.Amount > useBalanceInfo.Balance)
                return Problem("超出账户余额");
            useBalanceInfo.Balance -= dto.Amount;
            useWalletLog.Action = 7;
        }

        useWalletLog.UserId = dto.UId;
        useWalletLog.State = 1;
        var jurUser = _jurUserRepository.Where(x => x.Id == uId).First();
        if (jurUser == null)
            return Problem("管理账户错误");
        if (string.IsNullOrEmpty(dto.Img))
        {
            useWalletLog.Title = $"管理员:{jurUser.Name},操作描述:{dto.Title}";
        }
        else
        {
            useWalletLog.Title = $"管理员:{jurUser.Name},操作描述:{dto.Title},操作原因截图:{dto.Img}";
        }

        useWalletLog.Amount = dto.Amount;
        useWalletLog.FinishTime = DateTime.Now;
        _walletRepository.Update(useBalanceInfo);
        _walletLogRepository.Insert(useWalletLog);
        return new AppResult();
    }

    /// <summary>
    /// 调整推荐人前查询
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult<ChangeSuperiorFrontVo> ChangeSuperiorFront(int dto)
    {
        var data = _userRepository.Where(x => x.Code == dto)
            .Select(x => new ChangeSuperiorFrontVo()
            {
                SuperId = x.Id,
                SuperCode = x.Code,
                SuperName = x.Nickname,
                SuperTele = x.Tele,
                SuperGrade = x.Grade
            }).First();
        if (data == null)
            return Problem("上级不存在");
        return data;
    }
}